package com.xy.service.order;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xy.api.constant.UnitConstant;
import com.xy.api.constant.enums.UnitTypeEnum;
import com.xy.api.exception.BizException;
import com.xy.api.model.dto.mainData.ProductDTO;
import com.xy.api.model.dto.mainData.ProductInstanceDTO;
import com.xy.api.model.dto.mainData.ProductTreeNodeDTO;
import com.xy.api.model.dto.order.PlaceFollowOrderDTO;
import com.xy.api.model.dto.order.PlaceFollowOrderInstanceDTO;
import com.xy.api.model.request.order.PFOInstanceRequest;
import com.xy.api.model.request.order.PFOProductRequest;
import com.xy.api.model.request.order.SavePFOInstanceRequest;
import com.xy.api.model.request.order.SelectPFOInstanceRequest;
import com.xy.api.model.response.Rows;
import com.xy.api.service.common.IUnitService;
import com.xy.api.service.mainData.IProductInstanceService;
import com.xy.api.service.mainData.IProductService;
import com.xy.api.service.order.IPlaceFollowOrderInstanceService;
import com.xy.api.service.order.IPlaceFollowOrderService;
import com.xy.auth.UserContext;
import com.xy.mapper.order.PlaceFollowOrderInstanceMapper;
import com.xy.model.po.order.PlaceFollowOrderInstancePO;
import com.xy.utils.CustomBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PlaceFollowOrderInstanceServiceImpl implements IPlaceFollowOrderInstanceService {

    @Autowired
    private PlaceFollowOrderInstanceMapper placeFollowOrderInstanceMapper;

    @Autowired
    private IProductService productService;

    @Autowired
    private IProductInstanceService productInstanceService;

    @Autowired
    private IUnitService unitService;

    @Autowired
    private IPlaceFollowOrderService placeFollowOrderService;

    @Override
    public Rows<PlaceFollowOrderInstanceDTO> queryPFOInstanceList(PFOInstanceRequest request) {
        Assert.notNull(request.getPlaceFollowOrderId(), "工厂下单跟单ID必填");

        LambdaQueryWrapper<PlaceFollowOrderInstancePO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(PlaceFollowOrderInstancePO::getIsDeleted, false)
                .eq(PlaceFollowOrderInstancePO::getPlaceFollowOrderId, request.getPlaceFollowOrderId());
        List<PlaceFollowOrderInstancePO> placeFollowOrderInstancePOS = placeFollowOrderInstanceMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(placeFollowOrderInstancePOS)) {
            return new Rows<>(new ArrayList<>(), 0);
        }
        List<PlaceFollowOrderInstanceDTO> placeFollowOrderInstanceList = CustomBeanUtil.copyListProperties(placeFollowOrderInstancePOS, PlaceFollowOrderInstanceDTO::new);
        fillProductInstanceInfo(placeFollowOrderInstanceList);
        fillCalculateInfo(placeFollowOrderInstanceList);
        return new Rows<>(placeFollowOrderInstanceList, placeFollowOrderInstanceList.size());
    }

    private void fillCalculateInfo(List<PlaceFollowOrderInstanceDTO> placeFollowOrderInstanceList) {
        if (CollectionUtils.isEmpty(placeFollowOrderInstanceList)) {
            return;
        }
        for (PlaceFollowOrderInstanceDTO instance : placeFollowOrderInstanceList) {
            if (null != instance.getOuterCartonPackCount() && null != instance.getBoxNumber()) {
                BigDecimal count = BigDecimal.valueOf(instance.getOuterCartonPackCount() * instance.getBoxNumber());

                if (null != instance.getPayableShippingCostTotal()) {
                    BigDecimal payableShippingCost = instance.getPayableShippingCostTotal().divide(count, 2, RoundingMode.HALF_UP);
                    instance.setPayableShippingCost(payableShippingCost);
                }
                if (null != instance.getPayableTax()) {
                    BigDecimal payableTaxTotal = instance.getPayableTax().multiply(count).setScale(2, RoundingMode.HALF_UP);
                    instance.setPayableTaxTotal(payableTaxTotal);
                }
            }
        }
    }

    /**
     * 填充产品信息
     *
     * @param placeFollowOrderInstanceList
     */
    private void fillProductInstanceInfo(List<PlaceFollowOrderInstanceDTO> placeFollowOrderInstanceList) {
        if (CollectionUtils.isEmpty(placeFollowOrderInstanceList)) {
            return;
        }

        List<Long> productIdList = placeFollowOrderInstanceList.stream().map(e -> e.getProductId()).distinct().collect(Collectors.toList());
        List<ProductDTO> productList = productService.queryProductByIds(productIdList);
        if (CollectionUtils.isEmpty(productList)) {
            return;
        }
        Map<Long, ProductDTO> productMap = productList.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));

        List<Long> productInstanceIdList = placeFollowOrderInstanceList.stream().map(e -> e.getProductInstanceId()).distinct().collect(Collectors.toList());
        List<ProductInstanceDTO> productInstanceList = productInstanceService.queryProductInstanceByIds(productInstanceIdList);
        if (CollectionUtils.isEmpty(productInstanceList)) {
            return;
        }
        Map<Long, ProductInstanceDTO> productInstanceMap = productInstanceList.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));
        for (PlaceFollowOrderInstanceDTO item : placeFollowOrderInstanceList) {
            Long productInstanceId = item.getProductInstanceId();
            Long productId = item.getProductId();
            if (productInstanceMap.containsKey(productInstanceId) && productMap.containsKey(productId)) {
                ProductDTO product = productMap.get(productId);
                ProductInstanceDTO productInstance = productInstanceMap.get(productInstanceId);
                copyPropertiesFromProduct(product, productInstance, item);
            }
        }
    }

    /**
     * 从产品细则中复制属性
     *
     * @param source
     * @param target
     */
    private void copyPropertiesFromProduct(ProductDTO sourceProduct, ProductInstanceDTO source, PlaceFollowOrderInstanceDTO target) {
        if (null == source || target == null) {
            return;
        }
        target.setVariantCodeOneValue(source.getVariantCodeOneValue());
        target.setVariantCodeTwoValue(source.getVariantCodeTwoValue());
        target.setProductName(source.getProductName());
        target.setProductLength(source.getProductLength());
        target.setProductWidth(source.getProductWidth());
        target.setProductHeight(source.getProductHeight());
        target.setOuterCartonPackCount(source.getOuterCartonPackCount());
        target.setPacketLength(source.getPacketLength());
        target.setPacketWidth(source.getPacketWidth());
        target.setPacketHeight(source.getPacketHeight());
        target.setPacketTrueWeight(source.getPacketTrueWeight());

        String variantCodeOne = sourceProduct.getVariantCodeOne();
        String variantCodeTwo = sourceProduct.getVariantCodeTwo();
        String variantCodeOneValueWithDesc = variantCodeOne + "-" + source.getVariantCodeOneValue();
        String variantCodeTwoValueWithDesc = variantCodeTwo + "-" + source.getVariantCodeTwoValue();
        target.setVariantCodeOneValueWithDesc(variantCodeOneValueWithDesc);
        target.setVariantCodeTwoValueWithDesc(variantCodeTwoValueWithDesc);
    }

    @Override
    public void deletePFOInstance(Long id) {
        Assert.notNull(id, "工厂下单跟单细则ID必填");

        PlaceFollowOrderInstancePO deleteRecord = new PlaceFollowOrderInstancePO();
        deleteRecord.setId(id);
        deleteRecord.setIsDeleted(1);
        deleteRecord.setUpdateBy(UserContext.get().getId());
        placeFollowOrderInstanceMapper.updateById(deleteRecord);
    }

    @Override
    public void savePFOInstance(SavePFOInstanceRequest request) {
        Assert.notEmpty(request.getInstanceList(), "工厂下单跟单细则不能为空");
        List<PlaceFollowOrderInstancePO> instanceList = CustomBeanUtil.copyListProperties(request.getInstanceList(), PlaceFollowOrderInstancePO::new);

        PlaceFollowOrderDTO placeFollowOrder = placeFollowOrderService.queryById(request.getPlaceFollowOrderId());
        calculatePFOInstance(placeFollowOrder, instanceList);

        for (PlaceFollowOrderInstancePO instance : instanceList) {
            if (null != instance.getId()) {
                updatePFOInstance(instance);
            }
        }
    }

    private void calculatePFOInstance(PlaceFollowOrderDTO placeFollowOrder, List<PlaceFollowOrderInstancePO> instanceList) {
        if (CollectionUtils.isEmpty(instanceList)) {
            return;
        }
        BigDecimal logisticalPrice = placeFollowOrder.getLogisticalPrice();
        BigDecimal reverseRatio = placeFollowOrder.getReverseRatio();
        BigDecimal exchangeRate = placeFollowOrder.getExchangeRate();

        List<Long> productIdList = instanceList.stream().map(PlaceFollowOrderInstancePO::getProductId).distinct().collect(Collectors.toList());
        List<ProductDTO> productList = productService.queryProductByIds(productIdList);
        if (CollectionUtils.isEmpty(productList)) {
            throw new BizException("产品不存在");
        }
        Map<Long, ProductDTO> productMap = productList.stream().collect(Collectors.toMap(ProductDTO::getId, e -> e));

        List<Long> productInstanceIds = instanceList.stream().map(PlaceFollowOrderInstancePO::getProductInstanceId).collect(Collectors.toList());
        List<ProductInstanceDTO> productInstanceDTOS = productInstanceService.queryProductInstanceByIds(productInstanceIds);
        if (CollectionUtils.isEmpty(productInstanceDTOS)) {
            throw new BizException("产品不存在");
        }
        Map<Long, ProductInstanceDTO> productInstanceMap = productInstanceDTOS.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));

        BigDecimal hundred = BigDecimal.valueOf(100);
        for (PlaceFollowOrderInstancePO instance : instanceList) {
            Long productInstanceId = instance.getProductInstanceId();
            Long productId = instance.getProductId();

            if (null == instance.getBoxNumber()) {
                continue;
            }
            if (productInstanceMap.containsKey(productInstanceId) && productMap.containsKey(productId)) {
                ProductDTO product = productMap.get(productId);
                String productUnit = product.getProductUnit();
                ProductInstanceDTO productInstance = productInstanceMap.get(productInstanceId);

                if (null != logisticalPrice && null != productInstance.getPacketLength()
                        && null != productInstance.getPacketWidth() && null != productInstance.getPacketHeight()
                        && StringUtils.hasText(productUnit)
                ) {
                    //装箱体积（单位为立方米）
                    BigDecimal packetLength = unitService.convertUnit(UnitTypeEnum.LENGTH.getCode(), productUnit, UnitConstant.LengthUnitEnum.M.getCode(), productInstance.getPacketLength());
                    BigDecimal packetWidth = unitService.convertUnit(UnitTypeEnum.LENGTH.getCode(), productUnit, UnitConstant.LengthUnitEnum.M.getCode(), productInstance.getPacketWidth());
                    BigDecimal packetHeight = unitService.convertUnit(UnitTypeEnum.LENGTH.getCode(), productUnit, UnitConstant.LengthUnitEnum.M.getCode(), productInstance.getPacketHeight());
                    BigDecimal packetVolume = packetLength.multiply(packetWidth).multiply(packetHeight).setScale(4, RoundingMode.HALF_UP);

                    BigDecimal boxNumber = BigDecimal.valueOf(instance.getBoxNumber());

                    // 应付运费-总
                    BigDecimal payableShippingCostTotal = packetVolume.multiply(boxNumber).multiply(logisticalPrice).setScale(2, RoundingMode.HALF_UP);
                    instance.setPayableShippingCostTotal(payableShippingCostTotal);
                }
                if (null != reverseRatio && null != exchangeRate) {
                    BigDecimal rate = BigDecimal.valueOf(0.15);

                    BigDecimal payableTax = reverseRatio
                            .divide(hundred, 2, RoundingMode.HALF_UP)
                            .multiply(instance.getDeclarePrice())
                            .multiply(rate)
                            .multiply(exchangeRate);
                    instance.setPayableTax(payableTax);
                }
            }
        }
    }

    private void updatePFOInstance(PlaceFollowOrderInstancePO record) {
        record.setUpdateBy(UserContext.get().getId());
        placeFollowOrderInstanceMapper.updateById(record);
    }

    @Override
    @Transactional
    public List<PlaceFollowOrderInstanceDTO> selectPFOInstance(SelectPFOInstanceRequest request) {
        Assert.notNull(request.getPlaceFollowOrderId(), "工厂下单跟单ID必填");
        Assert.notEmpty(request.getSelectedList(), "产品为空");
        List<Long> productInstanceIdList = request.getSelectedList().stream().filter(e -> null != e.getProductInstanceId()).map(e -> e.getProductInstanceId()).collect(Collectors.toList());
        LambdaQueryWrapper<PlaceFollowOrderInstancePO> pFOInstanceQuery = new LambdaQueryWrapper<>();
        pFOInstanceQuery
                .eq(PlaceFollowOrderInstancePO::getIsDeleted, 0)
                .eq(PlaceFollowOrderInstancePO::getPlaceFollowOrderId, request.getPlaceFollowOrderId());
        List<PlaceFollowOrderInstancePO> pFOInstanceList = placeFollowOrderInstanceMapper.selectList(pFOInstanceQuery);
        Set<Long> existProductInstanceIdList = pFOInstanceList.stream().map(PlaceFollowOrderInstancePO::getProductInstanceId).collect(Collectors.toSet());

        List<ProductInstanceDTO> productInstanceList = productInstanceService.queryProductInstanceByIds(productInstanceIdList);
        if (CollectionUtils.isEmpty(productInstanceList)) {
            throw new BizException("产品细则不存在");
        }
        Map<Long, ProductInstanceDTO> productInstanceMap = productInstanceList.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));

        List<PlaceFollowOrderInstancePO> insertList = new ArrayList<>();
        for (Long productInstanceId : productInstanceIdList) {
            if (existProductInstanceIdList.contains(productInstanceId) || !productInstanceMap.containsKey(productInstanceId)) {
                continue;
            }
            PlaceFollowOrderInstancePO record = new PlaceFollowOrderInstancePO();
            record.setPlaceFollowOrderId(request.getPlaceFollowOrderId());
            record.setProductId(productInstanceMap.get(productInstanceId).getProductId());
            record.setProductInstanceId(productInstanceId);
            record.setCreateBy(UserContext.get().getId());

            placeFollowOrderInstanceMapper.insert(record);
            insertList.add(record);
        }
        List<PlaceFollowOrderInstanceDTO> placeFollowOrderInstanceList = CustomBeanUtil.copyListProperties(insertList, PlaceFollowOrderInstanceDTO::new);
        fillProductInstanceInfo(placeFollowOrderInstanceList);
        return placeFollowOrderInstanceList;
    }

    @Override
    public List<ProductTreeNodeDTO> queryProductTree(PFOProductRequest request) {
        List<ProductTreeNodeDTO> productTree = productService.queryProductTree(request.getVendorId(), request.getVendorProductTypeId());

        if (null != request.getPlaceFollowOrderId()) {
            LambdaQueryWrapper<PlaceFollowOrderInstancePO> pFOInstanceQuery = new LambdaQueryWrapper<>();
            pFOInstanceQuery
                    .eq(PlaceFollowOrderInstancePO::getIsDeleted, 0)
                    .eq(PlaceFollowOrderInstancePO::getPlaceFollowOrderId, request.getPlaceFollowOrderId());
            List<PlaceFollowOrderInstancePO> instancePOS = placeFollowOrderInstanceMapper.selectList(pFOInstanceQuery);
            if (!CollectionUtils.isEmpty(instancePOS)) {
                Set<Long> existProductInstanceSet = instancePOS.stream().map(e -> e.getProductInstanceId()).collect(Collectors.toSet());
                for (ProductTreeNodeDTO node : productTree) {
                    List<ProductTreeNodeDTO> children = node.getChildren();
                    if (CollectionUtils.isEmpty(children)) {
                        continue;
                    }
                    boolean alreadySelected = true;
                    for (ProductTreeNodeDTO child : children) {
                        if (existProductInstanceSet.contains(child.getProductInstanceId())) {
                            child.setAlreadySelected(true);
                        } else {
                            alreadySelected = false;
                            child.setAlreadySelected(false);
                        }
                    }
                    node.setAlreadySelected(alreadySelected);
                }
            }
        }
        return productTree;
    }
}
